//
//  FriendGroup.m
//  Guazi
//
//  Created by koolearn on 11-4-19.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "FriendGroup.h"
#import "DBConnection.h"
#import "Statement.h"
#import "User.h"
#import "GuaziAppDelegate.h"


@implementation FriendGroup


@synthesize groupId;
@synthesize userId;
@synthesize name;
@synthesize seq;
@synthesize createdAtString;
@synthesize createdAt;
@synthesize isPublic;
@synthesize isSync;
@synthesize friendCount;

@synthesize friends;

@synthesize index;
@synthesize startRowIndex;
@synthesize endRowIndex;
@synthesize expanded;
@synthesize loading;
@synthesize loaded;
@synthesize restored;


#pragma mark - 生命周期方法

- (void) dealloc
{
	[name release];
	[createdAtString release];
	[friends release];
	[super dealloc];
}


- (BOOL)isEqual:(id)anObject
{
	if ( anObject == nil ) return NO;
	if ( ![anObject isKindOfClass:[FriendGroup class]] ) return NO;
	if ( anObject == self ) return YES;
	
	FriendGroup* anGroup = (FriendGroup*) anObject;
	if ( anGroup.groupId == self.groupId ) return YES;
	return NO;
}


#pragma mark - 初始化方法

- (id) init
{
    self = [super init];
	if ( self ) {
		self.isPublic = NO;
		self.friendCount = 0;
		self.loaded = NO;
        self.loading = NO;
		self.expanded = NO;
		self.restored = NO;
        self.isSync = NO;
		self.friends = [NSMutableArray arrayWithCapacity:0];
	}
	return self;
}


+ (FriendGroup*) groupWithId:(sqlite_int64)agroupId name:(NSString*)aname
{
	FriendGroup* group = [[[FriendGroup alloc] init] autorelease];
	group.groupId = agroupId;
	group.name = aname;
	group.isPublic = NO;
    group.isSync = NO;
	group.expanded = NO;
	group.loaded = NO;
    group.loading = NO;
	group.friendCount = 0;
    group.userId = [GuaziAppDelegate getAppDelegate].user.userId;
    group.friends = [NSMutableArray arrayWithCapacity:0];
	return group;
}


+ (FriendGroup*) groupWithDictionary:(NSDictionary*)dic
{
	if ( dic == nil ) return nil;
	FriendGroup* group = [[[FriendGroup alloc] init] autorelease];
	group.groupId = [[dic objectForKey:@"groupId"] longLongValue];
	group.name = [dic objectForKey:@"name"];
	
	id o = [dic objectForKey:@"acce"];
	if ( o == nil || o == [NSNull null] ) {
		group.isPublic = NO;
	}
	else {
		group.isPublic = [o intValue]==1?YES:NO;
	}
	
	o = [dic objectForKey:@"relaNum"];
	if ( o == nil || o == [NSNull null] ) {
		group.friendCount = 0;
	}
	else {
		group.friendCount = [o intValue];
	}
    group.friends = [NSMutableArray arrayWithCapacity:group.friendCount];
	
	group.createdAtString = [dic objectForKey:@"created_at"];
	if ( group.createdAtString != nil && ![[NSNull null] isEqual:group.createdAtString] && [group.createdAtString length] > 0 ) {
		NSDateFormatter* f = [[NSDateFormatter alloc] init];
		[f setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
		NSDate* d = [f dateFromString:group.createdAtString];
		group.createdAt = [d timeIntervalSince1970];
		[f release];
	}
    
    group.isSync = YES;
    group.userId = [GuaziAppDelegate getAppDelegate].user.userId;
    
	return group;
}


+ (FriendGroup*) groupWithStatement:(Statement*)stmt
{
	FriendGroup* group = [[[FriendGroup alloc] init] autorelease];
	group.groupId = [stmt getInt64:0];
	group.name = [stmt getString:1];
	group.seq = [stmt getInt32:2];
	group.isPublic = ( [stmt getInt32:3]==1 ? YES : NO );
    group.isSync = ( [stmt getInt32:4] == 1 ? YES : NO );
	group.friendCount = [stmt getInt32:5];
    group.friends = [NSMutableArray arrayWithCapacity:group.friendCount];
    group.userId = [stmt getInt64:6];
	group.loaded = NO;
    group.loading = NO;
	group.expanded = NO;
	group.restored = NO;
	return group;
}


+ (FriendGroup*) groupWithGroup:(FriendGroup*)g
{
	FriendGroup* group = [[[FriendGroup alloc] init] autorelease];
	group.groupId = g.groupId;
	group.name = g.name;
	group.seq = g.seq;
	group.isPublic = g.isPublic;
    group.isSync = g.isSync;
	group.friendCount = g.friendCount;
    group.userId = g.userId;
    
    NSMutableArray* array = [NSMutableArray arrayWithCapacity:g.friendCount];
    for ( User* u in g.friends ) {
        [array addObject:u];
    }
    group.friends = array;
    
	return group;
}


- (NSDictionary*) dictionary
{
    NSMutableDictionary* dic = [NSMutableDictionary dictionaryWithCapacity:3];
    [dic setObject:[NSString stringWithFormat:@"%lld"] forKey:@"groupId"];
    [dic setObject:name forKey:@"name"];
    [dic setObject:(self.isPublic?@"1":@"2") forKey:@"acce"];
    [dic setObject:[NSString stringWithFormat:@"%ld", createAt] forKey:@"createdAt"];
    return dic;
}


#pragma mark - 分组下的用户操作

+ (void) setUsers:(NSArray*)users groupId:(sqlite_int64)groupId
{
	sqlite3* db = [DBConnection getDatabase];

    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;
    
	char* sql = "delete from friend_group_user where group_id = ? and owner_user_id = ?";
	Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
	[stmt bindInt64:groupId forIndex:1];
    [stmt bindInt64:ownerId forIndex:2];
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
	
	if ( users == nil || [users count] == 0 ) return;
	
	sql = "replace into friend_group_user (owner_user_id, user_id, group_id, seq) values (?,?,?,?)";
	for ( int i=0; i<[users count]; i++ ) {
		User* user = [users objectAtIndex:i];
		stmt = [[Statement alloc] initWithDB:db sql:sql];
        [stmt bindInt64:ownerId forIndex:1];
		[stmt bindInt64:user.userId forIndex:2];
		[stmt bindInt64:groupId forIndex:3];
		[stmt bindInt32:i forIndex:4];

		if ( [stmt step] != SQLITE_DONE ) {
			[stmt release];
			NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
			return;
		}
		[stmt release];
	}
}



- (NSMutableArray*) restoreUsers
{
	sqlite3* db = [DBConnection getDatabase];
	NSMutableArray* array = [NSMutableArray array];
	Statement* stmt = nil;
	
    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;

	if ( groupId == 0 ) {
        NSString* s = [NSString stringWithFormat:@"select %@, %@ from users u, user_relation r, friend_group_user g where u.user_id = r.user_id and r.owner_user_id = ? and g.owner_user_id = ? and g.group_id = 0 and (r.relation = '%@' or r.relation = '%@') order by u.name", kUserSQLUser, kUserSQLUserRelation, kUserRelationBoth, kUserRelationFollowing];
		char* sql = (char*) [s UTF8String];
		stmt = [[Statement alloc] initWithDB:db sql:sql];
        
        [stmt bindInt64:ownerId forIndex:1];
        [stmt bindInt64:ownerId forIndex:2];
	}
	else {
        NSString* s = [NSString stringWithFormat:@"select %@, %@ from users u, user_relation r, friend_group_user gu  where u.user_id = r.user_id and u.user_id = gu.user_id and gu.group_id = ? and gu.owner_user_id = ? and (r.relation = '%@' or r.relation = '%@') order by u.name", kUserSQLUser, kUserSQLUserRelation, kUserRelationBoth, kUserRelationFollowing];
		char* sql = (char*) [s UTF8String];
		stmt = [[Statement alloc] initWithDB:db sql:sql];
		[stmt bindInt64:groupId forIndex:1];
        [stmt bindInt64:ownerId forIndex:2];
	}
	
	
	while ( [stmt step] == SQLITE_ROW ) {
		User* user = [[User alloc] initWithStatement:stmt withRelation:YES];
		[array addObject:user];
        [user release];
	}
	
	[stmt release];
	
    self.friendCount = [array count];
	self.friends = array;
	self.restored = YES;
	
	return array;
}


#pragma mark - 分组操作

/*
 加载当前用户的所有分组
 */
+ (NSArray*) loadGroupsAndUsers
{
    sqlite3* db = [DBConnection getDatabase];
    
    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;
    NSString* sql = [NSString stringWithFormat:@"select %@, %@, %@ from friend_group g, friend_group_user gu, users u, user_relation r where g.id = gu.group_id and gu.user_id = u.user_id and u.user_id = r.user_id and g.owner_user_id = %lld and gu.owner_user_id = %lld and r.owner_user_id = %lld order by g.name, u.name", kUserSQLUser, kUserSQLUserRelation, kGroupSQLGroup, ownerId, ownerId, ownerId];
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:(char*)[sql UTF8String]];
    
    NSMutableArray* groups = [NSMutableArray array];
    NSMutableDictionary* groupDic = [NSMutableDictionary dictionary];
    
    FriendGroup* group1 = nil;
    FriendGroup* group2 = nil;
    long long groupId = -100;
    
    while ( [stmt step] == SQLITE_ROW ) {
        groupId = [stmt getInt64:23];
        FriendGroup* group = [groupDic objectForKey:[NSString stringWithFormat:@"%lld", groupId]];
        if ( !group ) {
            group = [[[FriendGroup alloc] init] autorelease];
            group.groupId = [stmt getInt64:23];
            group.name = [stmt getString:24];
            group.seq = [stmt getInt32:25];
            group.isPublic = ( [stmt getInt32:26]==1 ? YES : NO );
            group.isSync = ( [stmt getInt32:27] == 1 ? YES : NO );
            group.friendCount = [stmt getInt32:28];
            group.userId = [stmt getInt64:29];
            group.loaded = NO;
            group.loading = NO;
            group.expanded = NO;
            group.restored = YES;
            
            if ( group.groupId == -1 ) {
                group1 = group;
            }
            else if ( group.groupId == 0 ) {
                group2 = group;
            }
            else {
                [groups addObject:group];
            }
            
            [groupDic setObject:group forKey:[NSString stringWithFormat:@"%lld", groupId]];
        }

        User* user = [[User alloc] initWithStatement:stmt withRelation:YES];
        [group.friends addObject:user];
        [user release];
    }
    
    [stmt release];
    
    if ( group1 ) {
        [groups insertObject:group1 atIndex:0];
    }
    
    if ( group2 ) {
        [groups addObject:group2];
    }
    
    //for ( FriendGroup* group in groups ) {
    //    [group.friends sortUsingSelector:@selector(compare:)];
    //}
    
    return groups;
}


+ (NSArray*) loadGroups:(BOOL)includeUsers onlyRealGroup:(BOOL)realGroup
{
	sqlite3* db = [DBConnection getDatabase];
	
	NSMutableDictionary* userDic;
	
    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;

	if ( includeUsers ) {
		userDic = [NSMutableDictionary dictionary];
		NSMutableArray* array;
		
        NSString* sql = [NSString stringWithFormat:@"select %@, %@, g.group_id from users u, user_relation r, friend_group_user g where u.user_id = r.user_id and u.user_id = g.user_id and r.owner_user_id = ? and g.owner_user_id = ? order by g.group_id", kUserSQLUser, kUserSQLUserRelation];
		Statement* stmt = [[Statement alloc] initWithDB:db sql:(char*)[sql UTF8String]];
        [stmt bindInt64:ownerId forIndex:1];
        [stmt bindInt64:ownerId forIndex:2];
		
		while ( [stmt step] == SQLITE_ROW ) {
 			User* user = [[User alloc] initWithStatement:stmt withRelation:YES];
			sqlite_int64 groupId = [stmt getInt64:23];
			array = [userDic objectForKey:[NSNumber numberWithLongLong:groupId]];
			if ( array != nil ) {
				[array addObject:user];
			}
			else {
				array = [NSMutableArray array];
				[array addObject:user];
				[userDic setObject:array forKey:[NSNumber numberWithLongLong:groupId]];
			}
            [user release];
		}
		
		[stmt release];
        
        NSDictionary* statusDic = [FriendGroup loadContactStatuses];
        if ( [statusDic count] > 0 ) {
            for ( NSArray* arr in [userDic allValues] ) {
                for ( User* user in arr ) {
                    NSLog(@"userid=%lld", user.userId);
                    Status* status = [statusDic objectForKey:[NSString stringWithFormat:@"%lld", user.userId]];
                    if ( status ) {
                        user.status = status;
                    }
                }
            }
        }
        
	}
	
    NSString* sql = [NSString stringWithFormat:@"select %@ from friend_group g where g.owner_user_id = ? %@ order by g.name", kGroupSQLGroup, realGroup ? @"and g.id > 0" : @""];
	Statement* stmt = [[Statement alloc] initWithDB:db sql:(char*)[sql UTF8String]];
    [stmt bindInt64:ownerId forIndex:1];
	
	NSMutableArray* groupList = [NSMutableArray array];
	FriendGroup* group = nil;
    FriendGroup* firstGroup = nil;
    FriendGroup* lastGroup = nil;
    
	while ( [stmt step]==SQLITE_ROW ) {
		group = [FriendGroup groupWithStatement:stmt];
        
        if ( group.groupId == -1 ) {
            firstGroup = group;
        }
        else if ( group.groupId == 0 ) {
            lastGroup = group;
        }
        else {
            [groupList addObject:group];
        }
		
		if ( includeUsers ) {
			NSMutableArray* userList = [userDic objectForKey:[NSNumber numberWithLongLong:group.groupId]];
			if ( userList != nil ) {
				group.friends = userList;
				group.restored = YES;
			}
			else {
				group.friends = [NSMutableArray arrayWithObjects:nil];
				group.restored = YES;
			}
		}
	}
    
    [stmt release];
    
    if ( firstGroup ) {
        [groupList insertObject:firstGroup atIndex:0];
    }
    
    if ( lastGroup ) {
        [groupList addObject:lastGroup];
    }
	
	return groupList;
}


+ (NSDictionary*) loadContactStatuses
{
    NSString* sql = [NSString stringWithFormat:@"select * from contact_statuses cs where cs.user_id in (select u.user_id from users u, user_relation r where u.user_id = r.user_id and r.owner_user_id = ? and (r.relation = '%@' or r.relation = '%@')) order by created_at desc", kUserRelationBoth, kUserRelationFollowing];
    
    sqlite3* db = [DBConnection getDatabase];
    Statement* stmt = [[Statement alloc] initWithDB:db sql:(char*)[sql UTF8String]];
    [stmt bindInt64:[GuaziAppDelegate getAppDelegate].user.userId forIndex:1];
    
    NSMutableDictionary* dic = [NSMutableDictionary dictionary];
    while ( [stmt step]==SQLITE_ROW ) {
        Status* status = [Status statusWithStatement:stmt type:TWEET_TYPE_FRIENDS];
        NSLog(@"status.userid=%lld", status.user.userId);
        if ( status == nil ) continue;
        
        NSString* key = [NSString stringWithFormat:@"%lld",status.user.userId] ;
        if ( [dic objectForKey:key] == nil ) {
            [dic setObject:status forKey:key];
        }
    }
    
    [stmt release];
    
    return dic;
}


#pragma mark - 数据库操作

- (void) updateDB
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "replace into friend_group (id, name, seq, acce, is_sync, friend_count, created_at, owner_user_id) values (?,?,?,?,?,?,?,?)";
	
	Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
	[stmt bindInt64:groupId forIndex:1];
	[stmt bindString:name forIndex:2];
	[stmt bindInt32:seq forIndex:3];
	[stmt bindInt32:(isPublic?1:2) forIndex:4];
    [stmt bindInt32:(isSync?1:0) forIndex:5];
	[stmt bindInt32:friendCount forIndex:6];
	[stmt bindInt64:createdAt forIndex:7];
    [stmt bindInt64:userId forIndex:8];
	
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


+ (NSArray*) getGroupsWithUserId:(sqlite_int64)userId;
{
	sqlite3* db = [DBConnection getDatabase];
	char* sql = "select g.id, g.name, g.seq, g.acce, g.is_sync, g.friend_count, g.created_at from friend_group g, friend_group_user u where g.id = u.group_id and g.owner_user_id = ? and u.user_id = ? and g.id > 0";
	
	NSMutableArray* array = [NSMutableArray array];
	FriendGroup* group = nil;
	
	Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
    
    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;
    [stmt bindInt64:ownerId forIndex:1];
	[stmt bindInt64:userId forIndex:2];
	
	while ( [stmt step] == SQLITE_ROW ) {
		group = [FriendGroup groupWithStatement:stmt];
		[array addObject:group];
	}
	
	[stmt release];
	return array;
}





+ (void) insertGroupUser:(sqlite3_int64)userId groupId:(sqlite3_int64)agroupId seq:(NSInteger)aseq
{
    sqlite3* db = [DBConnection getDatabase];
    char* sql = "replace into friend_group_user (owner_user_id, user_id, group_id, seq) values (?,?,?,?)";
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:[GuaziAppDelegate getAppDelegate].user.userId forIndex:1];
    [stmt bindInt64:userId forIndex:2];
    [stmt bindInt64:agroupId forIndex:3];
    [stmt bindInt32:aseq forIndex:4];

	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


+ (void) deleteGroupUser:(sqlite3_int64)userId groupId:(sqlite3_int64)groupId
{
    sqlite3* db = [DBConnection getDatabase];
    char* sql = "delete from friend_group_user where user_id = ? and group_id = ? and owner_user_id = ?";
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:userId forIndex:1];
    [stmt bindInt64:groupId forIndex:2];
    [stmt bindInt64:[GuaziAppDelegate getAppDelegate].user.userId forIndex:3];
    
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


+ (void) deleteAllUserForGroup:(sqlite3_int64)groupId
{
    sqlite3* db = [DBConnection getDatabase];
    char* sql = "delete from friend_group_user where group_id = ? and owner_user_id = ?";
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:groupId forIndex:1];
    [stmt bindInt64:[GuaziAppDelegate getAppDelegate].user.userId forIndex:2];
    
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


+ (void) deleteAllGroupForUser:(sqlite3_int64)userId
{
    sqlite3* db = [DBConnection getDatabase];
    char* sql = "delete from friend_group_user where owner_user_id = ? and user_id = ? and group_id in (select id from friend_group where owner_user_id = ?) and group_id != -1";
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];

    long long ownerId = [GuaziAppDelegate getAppDelegate].user.userId;
    [stmt bindInt64:ownerId forIndex:1];
    [stmt bindInt64:userId forIndex:2];
    [stmt bindInt64:ownerId forIndex:3];
    
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


+ (void) deleteGroup:(sqlite3_int64)groupId
{
    sqlite3* db = [DBConnection getDatabase];
    char* sql = "delete from friend_group where id = ?";
    
    Statement* stmt = [[Statement alloc] initWithDB:db sql:sql];
    [stmt bindInt64:groupId forIndex:1];
    
	if ( [stmt step] != SQLITE_DONE ) {
		[stmt release];
		NSAssert2( 0, @"Fail to prepare statement: %s (%s)", sql, sqlite3_errmsg(db) );
		return;
	}
	
	[stmt release];
}


@end
